from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from category.models import Category
from category.serializers import CategorySerializer
from label.models import Label
from label.serializers import LabelSerializer
from note.models import Note
from note_dir.models import NoteDir
from user.models import User
from user.serializers import UserSerializer


class NoteSerializer(serializers.ModelSerializer):
    """笔记序列化器"""

    category = serializers.SerializerMethodField(read_only=True)
    label_list = serializers.SerializerMethodField(read_only=True)
    label_id_list = serializers.ListField(write_only=True, required=False)
    note_dir = serializers.SerializerMethodField(read_only=True)
    user = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Note
        exclude = ['user_id']
        read_only_fields = ['id', 'user_id', 'likes_num', 'is_delete']
        extra_kwargs = {
            'title': {'allow_blank': True, 'required': False},
            'content': {'allow_blank': True, 'required': False},
            'category_id': {'write_only': True, 'required': False},
            'dir_id': {'write_only': True, 'required': False},
        }

    def get_category(self, obj):
        category = Category.objects.filter(id=obj.category_id).first()
        if category:
            return CategorySerializer(category).data
        else:
            return None

    def get_note_dir(self, obj):
        note_dir = NoteDir.objects.filter(id=obj.dir_id).first()
        if note_dir:
            return {
                'id': note_dir.id,
                'title': note_dir.title,
            }
        else:
            return None

    def get_label_list(self, obj):
        if len(obj.label_id_list) == 0:
            return []
        label_id_list = obj.label_id_list.split('#')
        label_list = []
        for label_id in label_id_list:
            label_id = int(label_id)
            label = Label.objects.filter(id=label_id).first()
            if label:
                label_list.append(LabelSerializer(label).data)
        return label_list

    def get_user(self, obj):
        user = User.objects.filter(id=obj.user_id).first()
        if user:
            return UserSerializer(user).data
        else:
            return None

    # 重写 is_valid, 增加登录验证
    def is_valid(self, request=None, raise_exception=False):
        assert hasattr(self, 'initial_data'), (
            'Cannot call `.is_valid()` as no `data=` keyword argument was '
            'passed when instantiating the serializer instance.'
        )

        if not hasattr(self, '_validated_data'):
            try:
                self._validated_data = self.run_validation(self.initial_data)
            except ValidationError as exc:
                self._validated_data = {}
                self._errors = exc.detail
            else:
                self._errors = {}

        if self._errors and raise_exception:
            raise ValidationError(self.errors)

        if request:
            if request.session.get('uid') or User.objects.filter(id=request.session.get('uid')).first():
                self.user_id = request.session.get('uid')
            else:
                raise ValidationError({'usre_id': ['用户ID错误。']})

        return not bool(self._errors)

    # 重写 create
    def create(self, validated_data):
        label_id_list_str = ''
        if 'label_id_list' in validated_data:
            for label_id in validated_data.get('label_id_list'):
                label_id_list_str += str(label_id) + '#'
        validated_data['label_id_list'] = label_id_list_str[:len(label_id_list_str) - 1]
        return Note.objects.create(user_id=self.user_id, **validated_data)

    # 重写 udpate
    def update(self, instance, validated_data):
        if instance.user_id != self.user_id:
            raise ValidationError({'user_id': ['wrong user id']})
        else:
            label_id_list_str = ''
            if 'label_id_list' in validated_data:
                for label_id in validated_data.get('label_id_list'):
                    label_id_list_str += str(label_id) + '#'
            validated_data['label_id_list'] = label_id_list_str[:len(label_id_list_str) - 1]
            for attr, value in validated_data.items():
                setattr(instance, attr, value)
            instance.save()
            return instance
